/**
 * create by zhike date:2015年3月12日
 */
package com.acooly.module.openapi.client.provider.fbank.marshall;

import com.acooly.core.utils.Reflections;
import com.acooly.core.utils.Strings;
import com.acooly.module.openapi.client.api.exception.ApiClientException;
import com.acooly.module.openapi.client.api.marshal.ApiUnmarshal;
import com.acooly.module.openapi.client.api.message.MessageFactory;
import com.acooly.module.openapi.client.provider.fbank.FbankConstants;
import com.acooly.module.openapi.client.provider.fbank.domain.FbankNotify;
import com.acooly.module.openapi.client.provider.fbank.support.FbankAlias;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * @author zhike
 */
@Service
@Slf4j
public class FbankNotifyUnmarshall extends FbankMarshallSupport
        implements ApiUnmarshal<FbankNotify, Map<String, String>> {
    private static final Logger logger = LoggerFactory.getLogger(FbankNotifyUnmarshall.class);

    @Resource(name = "fbankMessageFactory")
    private MessageFactory messageFactory;

    @SuppressWarnings("unchecked")
    @Override
    public FbankNotify unmarshal(Map<String, String> notifyMessage, String serviceName) {
        try {
            log.info("异步通知报文{}", notifyMessage);
            // 验签

                String partnerId = notifyMessage.get("mchntId");
                SortedMap<String, String> sort = new TreeMap<String, String>(notifyMessage);
                verifySign(sort, partnerId);
            return doUnmarshall(notifyMessage, serviceName);
        } catch (Exception e) {
            throw new ApiClientException("异步通知 解析失败:" + e.getMessage());
        }
    }

    protected FbankNotify doUnmarshall(Map<String, String> message, String serviceName) {
        FbankNotify notify =
                (FbankNotify) messageFactory.getNotify(serviceName);
        Set<Field> fields = Reflections.getFields(notify.getClass());
        String key = null;
        for (Field field : fields) {
            FbankAlias fbankAlias = field.getAnnotation(FbankAlias.class);
            if (fbankAlias != null && Strings.isNotBlank(fbankAlias.value())) {
                key = fbankAlias.value();
            } else {
                key = field.getName();
            }
            Reflections.invokeSetter(notify, field.getName(), message.get(key));
        }
        return notify;
    }

    public void verifySign(SortedMap<String, String> params, String partnerId) {
        try {
            String signature = params.get(FbankConstants.SIGN_KEY);
            doVerifySign(params, signature, partnerId);
            log.info("验签成功");
        } catch (Exception e) {
            log.info("验签失败，响应报文：{}", params);
            throw new ApiClientException("响应报文验签失败");
        }
    }

    public void setMessageFactory(MessageFactory messageFactory) {
        this.messageFactory = messageFactory;
    }
}
